package com.study.thread.condition;

/**
 * @Description: 测试线程间的通信 Condition
 * @Author King
 * @Date 2024/12/15 16:16
 */
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import java.util.logging.Level;
import java.util.logging.Logger;

public class ProducerConsumerExample {
    private static final Logger logger = Logger.getLogger(ProducerConsumerExample.class.getName());
    private final Lock lock = new ReentrantLock();
    private final Condition notFull = lock.newCondition();
    private final Condition notEmpty = lock.newCondition();
    private final int[] buffer = new int[10];
    private int count = 0;

    public void produce() throws InterruptedException {
        lock.lock();
        try {
            // 保持 while 循环以防止虚假唤醒
            while (count == buffer.length) {
                logger.log(Level.FINE, "Buffer is full, producer waits.");
                notFull.await(); // 等待buffer未满的条件
            }
            // 生产一个产品
            buffer[count++] = 1;
            logger.log(Level.INFO, "Produced one item, current count: {0}", count);
            notEmpty.signal(); // 唤醒一个等待buffer非空的消费者
        } finally {
            lock.unlock();
        }
    }

    public void consume() throws InterruptedException {
        lock.lock();
        try {
            while (count == 0) {
                logger.log(Level.FINE, "Buffer is empty, consumer waits.");
                notEmpty.await(); // 等待buffer非空的条件
            }
            // 消费一个产品
            --count;
            logger.log(Level.INFO, "Consumed one item, current count: {0}", count);
            notFull.signal(); // 唤醒一个等待buffer未满的生产者
        } finally {
            lock.unlock();
        }
    }

    public static void main(String[] args) {
        ProducerConsumerExample example = new ProducerConsumerExample();

        Thread producerThread = new Thread(() -> {
            for (int i = 0; i < 20; ++i) {
                try {
                    example.produce();
                } catch (InterruptedException e) {
                    Thread.currentThread().interrupt();
                    logger.log(Level.SEVERE, "Producer interrupted", e);
                }
            }
        });

        Thread consumerThread = new Thread(() -> {
            for (int i = 0; i < 20; ++i) {
                try {
                    example.consume();
                } catch (InterruptedException e) {
                    Thread.currentThread().interrupt();
                    logger.log(Level.SEVERE, "Consumer interrupted", e);
                }
            }
        });

        producerThread.start();
        consumerThread.start();
    }
}